package com.da.core.app;

import com.da.core.context.Context;
import com.da.core.context.Session;
import com.da.core.middleware.Middleware;
import com.da.core.middleware.MiddlewareChain;
import com.da.core.trie.RouteTrie;
import com.da.core.trie.TrieNode;

import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @author da
 * @time 2023/9/16 上午 10:47
 */
public interface BaseApp {
    /**
     * 路由组
     */
    Map<String, RouteTrie> routers = new HashMap<String, RouteTrie>() {{
        put("GET", new RouteTrie());
        put("POST", new RouteTrie());
        put("PUT", new RouteTrie());
        put("DELETE", new RouteTrie());
    }};

    /**
     * 框架中间件
     */
    List<Middleware> middlewares = new ArrayList<>();
    /**
     * 中间件管理者
     */
    MiddlewareChain chain = new MiddlewareChain(middlewares);

    /**
     * 注册路由
     *
     * @param method 请求方法
     * @param path   url
     * @param func   处理器
     */
    default void registerRouter(String method, String path, Handler func) {
        verifyPath(path);
        RouteTrie routeTrie = this.routers.get(method);
        TrieNode routeNode = routeTrie.search(path);
        if (null != routeNode && routeNode.getParams().isEmpty()) {
            Handler handler = routeNode.getHandler();
            if (null != handler) {
                throw new RuntimeException("路由冲突,前面已经注册了当前路由[" + path + "]");
            }
        }
        routeTrie.insert(path, func);
        System.out.println("注册了路由 [" + method + " " + path + "]");
    }

    /**
     * 验证路由是否合法
     *
     * @param path url
     */
    default void verifyPath(String path) {
        if (null == path || path.isEmpty()) {
            throw new RuntimeException("路由不能为null或者为空");
        }
        if (!path.startsWith("/")) {
            throw new RuntimeException("路由必须以/开头 当前注册的路由为[" + path + "]");
        }
        if (!path.equals("/")) {
            if (path.endsWith("/")) {
                throw new RuntimeException("路由不允许以/结尾 当前注册的路由为[" + path + "]");
            }
            for (String s : path.substring(1).split("/")) {
                if (s.isEmpty()) {
                    throw new RuntimeException("路由不能连续出现/ 当前注册的路由为[" + path + "]");
                }
            }
        }
    }

    /**
     * 注册GET请求
     *
     * @param path url
     * @param func 处理器
     */
    default void GET(String path, Handler func) {
        this.registerRouter("GET", path, func);
    }

    /**
     * 注册POST请求
     *
     * @param path url
     * @param func 处理器
     */
    default void POST(String path, Handler func) {
        this.registerRouter("POST", path, func);
    }

    /**
     * 注册PUT请求
     *
     * @param path url
     * @param func 处理器
     */
    default void PUT(String path, Handler func) {
        this.registerRouter("PUT", path, func);
    }

    /**
     * 注册DELETE请求
     *
     * @param path url
     * @param func 处理器
     */
    default void DELETE(String path, Handler func) {
        this.registerRouter("DELETE", path, func);
    }

    /**
     * 注册SSE请求
     *
     * @param path url
     * @param func 处理器
     */
    default void SSE(String path, Handler func) {
//        注册路由
        this.GET(path, ctx ->
        {
//            不关闭当前通道,让当前通道后续继续使用
            ctx.setCloseChannel(false);
//            传递当前上下文(用新的进程去处理,不然会阻塞其他请求)

            new Thread(() -> func.callback(ctx)).start();
//            初始化SSE连接,中间件会刷新数据到浏览器
            ctx.setHeader("Content-Type", "text/event-stream");
            ctx.setHeader("Cache-Control", "no-cache");
            ctx.setHeader("Connection", "keep-alive");
            ctx.setStatus(200);
            ctx.setStatusMsg("OK");
            ctx.setData("{\"event\":\"update\",\"data\":\"创建SSE连接成功\"}".getBytes(StandardCharsets.UTF_8));
        });

    }

    /**
     * 注册用户中间件
     *
     * @param middlewares 自定义的中间件
     */
    default void middleware(Middleware... middlewares) {
        this.middlewares.addAll(Arrays.asList(middlewares));
    }

    /**
     * 处理浏览器发来的请求
     *
     * @param ctx 上下文
     */
    default void handleRequest(Context ctx) {
//        nio模式下,刷新浏览器会有null的情况发生
        if (null == ctx.getMethod() || null == ctx.getUrl()) {
            return;
        }
//        获取路由对应的处理函数执行
        RouteTrie routeTrie = this.routers.get(ctx.getMethod());
        if (null == routeTrie) throw new RuntimeException("没有找到 [" + ctx.getMethod() + "] 对应的处理函数");
//        获取静态路由
        TrieNode routeNode = routeTrie.search(ctx.getUrl());
        if (null != routeNode) {
            Handler handlerFunc = routeNode.getHandler();
            if (null != handlerFunc) {
                try {
//                    合并params参数
                    ctx.getParams().putAll(routeNode.getParams());
                    handlerFunc.callback(ctx);
                } catch (Exception e) {
//                把错误交给错误处理的中间件处理
                    ctx.setException(e);
                }
            } else {
                ctx.setStatus(404);
                ctx.setStatusMsg("OK");
                ctx.setHeader("Content-Type", "text/plain;charset=utf-8;");
                ctx.setData("404 NOT FOUND".getBytes(StandardCharsets.UTF_8));
            }
        } else {
            ctx.setStatus(404);
            ctx.setStatusMsg("OK");
            ctx.setHeader("Content-Type", "text/plain;charset=utf-8;");
            ctx.setData("404 NOT FOUND".getBytes(StandardCharsets.UTF_8));
        }
//        执行中间件
        chain.init();
        chain.next(ctx);
    }

    /**
     * 获取 session
     *
     * @return session对象
     */
    Session getSession();

    /**
     * 设置启动端口
     *
     * @param port 端口
     */
    void start(int port);

    void setSession(Session session);
}
